import os
import sys

AbsolutePath = os.path.abspath(__file__)
SuperiorCatalogue = os.path.dirname(AbsolutePath)
BaseDir = os.path.dirname(SuperiorCatalogue)
sys.path.insert(0, SuperiorCatalogue)

import subprocess
import asyncio
import re
import time
from typing import Tuple, Optional
import serial
import threading
from queue import Queue

from TestToolApi import Debug
from BaiDuApi import Map


class MainBoard:

    def __init__(self, logging=True):
        # <<<<<<<<<< 变量类别 >>>>>>>>>> #
        # @self.__RESULT[dict]: 结果集合字典
        # @self.__glDebugQueue[Queue]: 全局调试通道
        # @self.__glDebug[Debug]: 全局调试对象
        # @self.__netDevSpeed[list]: 各网卡实时流量字典 
        self.__RESULT = {"cpuUsage": Optional[float],
                         "cpuTemp": Optional[float],
                         "memPer": Optional[float],
                         "memTotal": Optional[float],
                         "memFree": Optional[float],
                         "diskTotal": Optional[float],
                         "diskUsed": Optional[float],
                         "diskFree": Optional[float],
                         "diskPer": Optional[float],
                         "netInfo": Optional[dict]
                         }
        if logging:
            self.__glDebugQueue = Queue(5)
        else:
            self.__glDebugQueue = None
        self.__glDebug = Debug(self.__glDebugQueue, time_switch=True, debug_name='下位机系统-主板信息模块')
        self.__netDevSpeed = {}
        self.__threadMBScan = None
        self.__threadMBScanStatus = False
        self.__initScan()

    @staticmethod
    def __cmd_run(command: str):

        # args = shlex.split(command)
        # print(args)
        sb = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
        stdout, stderr = sb.communicate()
        if stdout:
            return stdout.decode()
        if stderr:
            return stderr.decode()
        # print("cmdEnd")

    def __cpu_usage(self):
        """
        返回值：返回CPU使用率
        """
        result = self.__cmd_run("top -n1 | awk '/Cpu\(s\):/ {print $2}'")
        result.strip()
        result = float(result)
        self.__RESULT["cpuUsage"] = result

    def __cpu_temp(self):
        """
        *需要使用树莓派，不然无法使用vcgencmd指令查询cpu温度
        返回值：返回CPU温度
        """
        # print("cpuTempRun")
        result = self.__cmd_run('vcgencmd measure_temp')
        result = result.replace("temp=", "").replace("'C\n", "")
        result = float(result)
        self.__RESULT["cpuTemp"] = result

    def __mem_usage(self):
        """
        返回值：返回内存状况元组
        (内存使用率: float %,
        内存总量: float MB,
        内存使用量: float MB,
        内存剩余量: float MB)
        """
        # print("memUsageRun")
        result = self.__cmd_run("free")
        line = result.split('\n')[1]
        RAM_TOTAL, RAM_USED, RAM_FREE = line.split()[1:4]
        RAM_TOTAL = round(int(RAM_TOTAL) / 1000, 2)
        RAM_USED = round(int(RAM_USED) / 1000, 2)
        RAM_FREE = round(int(RAM_FREE) / 1000, 2)
        RAM_USAGE = round(RAM_USED / RAM_TOTAL * 100, 2)
        # return RAM_USAGE, RAM_TOTAL, RAM_USED, RAM_FREE
        self.__RESULT["memPer"] = RAM_USAGE
        self.__RESULT["memUsed"] = RAM_USED
        self.__RESULT["memFree"] = RAM_FREE
        self.__RESULT["memTotal"] = RAM_TOTAL

    def __disk_usage(self):
        """
        返回值：返回一个硬盘状况元组
        (硬盘总大小: float,
        硬盘已使用: float,
        硬盘未使用: float,
        硬盘使用率: float %)
        """
        # print("diskUsageRun")
        result = self.__cmd_run("df -h /")
        line = result.split("\n")[1]
        DISK_TOTAL, DISK_USED, DISK_AVALIBLE, DISK_PERC = line.split()[1: 5]
        DISK_TOTAL = round(float(DISK_TOTAL.replace('G', '')), 2)
        DISK_USED = round(float(DISK_USED.replace('G', '')), 2)
        DISK_AVALIBLE = round(float(DISK_AVALIBLE.replace('G', '')), 2)
        DISK_PERC = round(float(DISK_PERC.replace('%', '')), 2)
        # return DISK_TOTAL, DISK_USED, DISK_AVALIBLE, DISK_PERC
        self.__RESULT["diskTotal"] = DISK_TOTAL
        self.__RESULT["diskUsed"] = DISK_USED
        self.__RESULT["diskFree"] = DISK_AVALIBLE
        self.__RESULT["diskPer"] = DISK_PERC

    def __net_flu(self):
        """
        @param: None
        @return: {
            "totalNetDevNum": (int)
            "devList" : [
                {
                    "devName":"eth0",
                    "receive":{
                        "bytes": (int),
                        "packets": (int),
                        "errs": (int),
                        "drop": (int),
                    },
                    "transmit":{
                        "bytes": (int),
                        "packets": (int),
                        "errs": (int),
                        "drop": (int),
                    }
                },
                ...
            ]
        }
        """
        # print("netFluRun")
        result = self.__cmd_run("cat /proc/net/dev")
        result = re.split(r'\n', result)
        contentList = []
        for i in range(2, len(result) - 1):
            result_NL = result[i].split(':')
            propertyList = re.findall(r'(\d+)', result_NL[1])
            resultList = propertyList
            devName = result_NL[0].strip()
            recv_bytes = int(resultList[0])
            recv_packets = int(resultList[1])
            recv_errs = int(resultList[2])
            recv_drop = int(resultList[3])
            trans_bytes = int(resultList[8])
            trans_packets = int(resultList[9])
            trans_errs = int(resultList[10])
            trans_drop = int(resultList[11])
            contentList.append(
                {
                    "devName": devName,
                    "receive": {
                        "bytes": recv_bytes,
                        "packets": recv_packets,
                        "errs": recv_errs,
                        "drop": recv_drop,
                    },
                    "transmit": {
                        "bytes": trans_bytes,
                        "packets": trans_packets,
                        "errs": trans_errs,
                        "drop": trans_drop,
                    },
                }
            )
        realResultDic = {
            "totalNetDevNum": len(result) - 2,
            "devList": contentList
        }
        self.__RESULT["netInfo"] = realResultDic

    def __updateMB(self, waitTime):
        """
        返回一个字典:
        __cpuUsage, __cpuTemp, __memPer, __memTotal
        memUsage, __memFree, __diskTotal, __diskUsed,
        __disFree, __diskPer, netInfo
        """
        while True:
            if not self.__threadMBScanStatus:
                self.__glDebug.warn("主板模块请求结束线程，即将关闭该线程！")
                break
            self.__cpu_usage()
            self.__cpu_temp()
            self.__mem_usage()
            self.__disk_usage()
            self.__net_flu()
            self.__countRecvDevNetSpeed()
            self.__countSendDevNetSpeed()
            # print(self.__netDevSpeed)
            time.sleep(waitTime)

    def __initScan(self):
        self.__glDebug.info("主板模块数据初始化中")
        self.__cpu_usage()
        self.__cpu_temp()
        self.__mem_usage()
        self.__disk_usage()
        self.__net_flu()
        for each in self.__RESULT["netInfo"]["devList"]:
            self.__netDevSpeed[each['devName']] = {
                "send": {
                    "lastBytes": each["transmit"]["bytes"],
                    "nowData": 0
                },
                "recv": {
                    "lastBytes": each["receive"]["bytes"],
                    "nowData": 0
                }
            }

    def openMBScan(self, waitTime: float = 1):
        """
        描述：打开主板信息获取线程，将会随时更新主板信息
        参数：@waitTime[float]->每次主板数据的采样周期
        返回值：无
        """
        if self.__threadMBScan is None:
            self.__threadMBScanStatus = True
            self.__threadMBScan = threading.Thread(target=self.__updateMB, args=(waitTime,))
            self.__threadMBScan.setDaemon(True)
            self.__threadMBScan.start()
            self.__glDebug.info("主板信息获取线程打开成功!")
        else:
            self.__glDebug.warn("主板信息获取线程已打开，请不要重复打开！")

    def closeMBScan(self):
        if self.__threadMBScan is None:
            self.__glDebug.info("主板信息获取线程并未打开，关闭失败！")
        else:
            self.__threadMBScanStatus = False
            self.__threadMBScan.join()
            self.__threadMBScan = None
            self.__glDebug.warn("主板信息获取线程成功关闭！")

    def getCpuUsage(self) -> Optional[float]:
        """
        描述：得到CPU使用率
        参数：无
        返回值：CPU的使用率百分比[float]->xx.x(%)
        """
        try:
            return self.__RESULT["cpuUsage"]
        except:
            return None

    def getCpuTemp(self) -> Optional[float]:
        """
        描述：得到CPU温度
        参数：无
        返回值：CPU的温度[float]->xx.x(°C)
        """
        try:
            return self.__RESULT["cpuTemp"]
        except:
            return None

    def getMemPer(self) -> Optional[float]:
        """
        描述：得到内存使用率
        参数：无
        返回值：内存使用率[float]->xx.x(%)
        """
        try:
            return self.__RESULT["memPer"]
        except:
            return None

    def getMemTotal(self) -> Optional[float]:
        """
        描述：得到内存总量
        参数：无
        返回值：内存总量[float]->xx.x(MB)
        """
        try:
            return self.__RESULT["memTotal"]
        except:
            return None

    def getMemUsed(self) -> Optional[float]:
        """
        描述：得到内存当前使用量
        参数：无
        返回值：内存使用量[float]->xx.x(MB)
        """
        try:
            return self.__RESULT["memUsed"]
        except:
            return None

    def getMemFree(self) -> Optional[float]:
        """
        描述：内存可用量
        参数：无
        返回值：内存可用量[float]->xx.x(MB)
        """
        try:
            return self.__RESULT["memFree"]
        except:
            return None

    def getDiskTotal(self) -> Optional[float]:
        """
        描述：内存当前使用量
        参数：无
        返回值：内存当前使用量[float]->xx.x(MB)
        """
        try:
            return self.__RESULT["diskTotal"]
        except:
            return None

    def getDiskUsed(self) -> Optional[float]:
        """
        描述：磁盘使用量
        参数：无
        返回值：磁盘使用量[float]->xx.x(GB)
        """
        try:
            return self.__RESULT["diskUsed"]
        except:
            return None

    def getDiskFree(self) -> Optional[float]:
        """
        描述：磁盘剩余量
        参数：无
        返回值：磁盘剩余量[float]->xx.x(GB)
        """
        try:
            return self.__RESULT["diskFree"]
        except:
            return None

    def getDiskPer(self) -> Optional[float]:
        """
        描述：磁盘使用率
        参数：无
        返回值：磁盘使用率[float]->xx.x(%)
        """
        try:
            return self.__RESULT["diskPer"]
        except:
            return None

    def getDevNameList(self) -> Optional[tuple]:
        """
        描述：得到设备列表
        参数：无
        返回值：设备列表[list]
        """
        try:
            devList = [each['devName'] for each in self.__RESULT["netInfo"]["devList"]]
            return tuple(devList)
        except:
            return None

    def __countRecvDevNetSpeed(self):
        for each in self.__RESULT["netInfo"]["devList"]:
            nowData = each["receive"]["bytes"] - \
                      self.__netDevSpeed[each["devName"]]["recv"]["lastBytes"]
            self.__netDevSpeed[each["devName"]]["recv"]["nowData"] = nowData / 1024
            self.__netDevSpeed[each["devName"]]["recv"]["lastBytes"] = each["receive"]["bytes"]

    def __countSendDevNetSpeed(self):
        for each in self.__RESULT["netInfo"]["devList"]:
            # print("当前", each['transmit']['bytes'])
            # print("之前", self.__netDevSpeed[each["devName"]]["send"]["lastBytes"])
            nowData = each["transmit"]["bytes"] - \
                      self.__netDevSpeed[each["devName"]]["send"]["lastBytes"]
            self.__netDevSpeed[each["devName"]]["send"]["nowData"] = nowData / 1024
            self.__netDevSpeed[each["devName"]]["send"]["lastBytes"] = each["transmit"]['bytes']

    def getNetDevSpeed(self, devName) -> Optional[Tuple[float, float]]:
        """
        描述：得到网卡的实时流量
        参数：@devName[str]->通过DevNameList获得的网卡名
        返回值：返回该网卡当前的下载和上传流量(float, float)->单位KB
        """
        try:
            recvData = self.__netDevSpeed[devName]["recv"]["nowData"]
            sendData = self.__netDevSpeed[devName]["send"]["nowData"]
            return recvData, sendData
        except:
            return None


class NetWork:

    def __init__(self, logging=True):
        # <<<<<<<<<< 全局参变量列表 >>>>>>>>>> #
        # @self.__glDebugQueue[Queue]: 全局调试信息输出信道
        # @self.__threadNet[threading.Thread]: 网络线程对象
        # @self.__threadGPS[threading.Thread]: GPS线程对象
        # @self.__gpsStatus[Bool]: GPS是否打开
        # @self.__gpsDebug[Debug]: gps线程调试对象
        # @self.__glDebug[Debug]: 默认全局调试对象
        # @self.__netDebug[Debug]: 网络线程调试对象
        # @self.__gpsDict[dict]: GPSPRMC的数据字典
        if logging:
            self.__glDebugQueue = Queue(5)
        else:
            self.__glDebugQueue = None

        self.__glDebug = Debug(self.__glDebugQueue, True, '下位机系统-网络模块')
        self.__threadGPS = None
        self.__threadGPSStat = False

        self.__gpsDict = {'time': None, 'locStat': None, 'dim': None,
                          'nsDim': None, 'lit': None, 'ewLit': None, 'gdRate': None,
                          'gdDirect': None, 'date': None}

        # ---------- 扫描4G模块是否连通主板 ---------- #
        # @self.__netStatus[Bool]: 网络连接状态
        # @self.__netRunStatus[Bool]: 网络正在连接状态
        netRes = None
        if self.__cmd_("ls -l /dev | grep ttyUSB") is None:
            raise RuntimeError("[CenterSystem_Network]: 网络模块没有检测到！")
        netRes = self.__cmd_('sudo ip route | grep "via 10.64.64.64"')
        if netRes is not None:
            self.__netStatus = True
        else:
            self.__netStatus = False

        # ---------- 设备串口初始化 ---------- #
        # @self.__serial_normal[serial.Serial]: 日常AT指令串口接口
        # @self.__serial_gps[seral.Serial]: GPS信息串口接口
        self.__serial_normal = serial.Serial("/dev/ttyUSB3", 115200, timeout=1)
        self.__serial_gps = serial.Serial("/dev/ttyUSB1", 115200, timeout=1)
        self.__glDebug.info("网络模块串口初始化完成!")

        # ---------- 设备信息自检 ---------- #
        result = self.__runAT(
            ['AT+CMEE=2', 'AT+QURCCFG="URCPORT","usbat"', 'AT+CMGF=0'])
        result = self.__runAT(['ATI', 'AT+CPIN?', 'AT+CSQ?',
                               'AT+CREG?', 'AT+CGREG?', 'AT+COPS?', 'AT+QCCID', 'AT+CIMI'])
        self.__runAT(['AT+QGPS=1'])
        ManufacturerID = result[0][1]
        DeviceModule = result[0][2]
        FirmwareVersion = result[0][3]
        SIM_IMSI = result[6][1]
        SIM_ICCID = result[7][1]
        res = self.__runAT(['AT+CSCA?'])[0]
        res_csca = res[1]
        res_number = re.search(r"\+\d+", res_csca).group()
        CENTER_NUMBER = res_number.replace("+86", '')
        self.__glDebug.info("模块初始化完成获得以下信息")
        self.__glDebug.info("厂家:{} 型号:{} 版本:{}".format(
            ManufacturerID, DeviceModule, FirmwareVersion))
        self.__glDebug.info("SIM_IMSI:{} SIM_ICCID{}".format(
            SIM_IMSI, SIM_ICCID))
        self.__glDebug.info("短信服务中心号码:{}".format(CENTER_NUMBER))

    async def __cmd_run(self, command: str, times: int = 3):
        proc = await asyncio.create_subprocess_shell(
            command,
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.PIPE
        )
        stdout, stderr = await proc.communicate()
        if stdout:
            return stdout.decode()
        if stderr:
            return stderr.decode()

    def __cmd_(self, command: str, times: int = 3):
        sub = subprocess.Popen(command, shell=True,
                               stderr=subprocess.PIPE, stdout=subprocess.PIPE)
        sub.wait(times)
        stdout, stderr = sub.communicate()
        if stdout and stderr:
            return stdout, stderr
        elif stdout:
            return stdout
        elif stderr:
            return stderr
        else:
            return None

    async def __at_normal(self, command: str, waittime: int = 5) -> list:
        """
        __at_normal 向串口执行AT指令

        私有类，不可修改

        Parameters
        ----------
        command : str
            需要发送的AT命令字符串
        waittime : int, optional
            超时时间，超时后结束循环, by default 5

        Returns
        -------
        list
            返回字符串列表
        """
        num = 0
        # await asyncio.sleep(0.01)
        if re.search(r'\^Z', command) == None:
            self.__serial_normal.write(
                (command + "\r").encode('ascii', 'ignore'))
        else:
            self.__serial_normal.write(command.replace(
                '^Z', chr(26)).encode('ascii', 'ignore'))
        result = b'\r\n'
        resultList = []
        while (result != b'OK\r\n' and result != b'ERROR\r\n' and (
                re.search('ERROR', result.decode()) is None)) and num <= waittime:
            result = self.__serial_normal.readline()
            if result == b'':
                num += 1
            elif result == b'> ':
                # print(result)

                resultList.append(result.decode().replace(
                    '\r', '').replace('\n', ''))
                # print("[CenterSystem]: 已进入发送短信模式，请输入pdu码后再加上^Z")
                return resultList
            else:
                resultList.append(result.decode().replace(
                    '\r', '').replace('\n', ''))
                # print(result)
        return resultList
        # print("-----------")

    async def __async_main(self, aws: list):
        """
        __async_main 异步AT指令执行口

        私有类，不可调用和修改

        Parameters
        ----------
        aws : list
            传入的AT字符串列表

        Returns
        -------
        list    
            返回二维字符串列表结果集
        """
        result = await asyncio.gather(*aws)
        return result

    def __runAT(self, strList: list, waittime: int = 3) -> list:
        """
        __runAT 异步运行AT指令集

        Parameters
        ----------
        strList : list
            需要传入的指令集合

        Returns
        -------
        list
            返回指令运行完成后的二维列表
        """
        commandList = []
        for each in strList:
            commandList.append(
                self.__at_normal(each, waittime=waittime))
        resultList = asyncio.run(self.__async_main(commandList))
        return resultList

    def getNetStatus(self) -> tuple:
        """
        描述：得到4G模块的信号状态
        参数：无
        返回值：信号状态[tuple]->(信号强度[int]<0~5>, 有效性[bool])
        """
        res = self.__runAT(['AT+CSQ'])[0]
        reslist = re.search(r'\d+,\d+', res[1]).group().split(',')
        signalOk = True
        if reslist[0] == '99':
            signalOk = False
            signalStatus = 0
        else:
            if (-113 + int(reslist[0]) * 2) > -85:
                signalStatus = 5
            elif -85 >= (-113 + int(reslist[0]) * 2) > -90:
                signalStatus = 4
            elif -90 >= (-113 + int(reslist[0]) * 2) > -95:
                signalStatus = 3
            elif -95 >= (-113 + int(reslist[0]) * 2) > -100:
                signalStatus = 2
            elif -100 >= (-113 + int(reslist[0]) * 2) > -105:
                signalStatus = 1
            else:
                signalOk = False
                signalStatus = 0
        return signalStatus, signalOk

    def getNetOpened(self) -> bool:
        """
        描述：得到网络是否打开
        参数：无
        返回值：联网状态[bool]
        """
        return self.__netStatus

    def __updateGPRMC(self):
        """
        描述：更新最小定位信息数据包
        参数：无
        返回值：无
        """
        while True:
            if not self.__threadGPSStat:
                self.__glDebug.warn("父线程请求终结GPS数据更新线程，即将关闭该线程!")
                break
            else:
                result = self.__serial_gps.readline()
                result = result.decode().strip()
                if re.search(r'\$GPRMC', result) is not None:
                    resList = result.split(',')
                    # ---------- 时间 ---------- #
                    timeStr = resList[1].split('.')[0]
                    if timeStr != '':
                        timeH, timeM, timeS = re.findall(r'\w{2}', timeStr)
                        timeH = int(timeH) + 8 - 24 if int(timeH) + 8 >= 24 else int(timeH) + 8
                        timeRes = f"{timeH}:{timeM}:{timeS}"
                    else:
                        timeRes = None
                    self.__gpsDict['time'] = timeRes
                    # ---------- 定位状态 ---------- #
                    locStat = resList[2]
                    if locStat == 'A':
                        locRes = True
                    elif locStat == 'V':
                        locRes = False
                    else:
                        locRes = None
                    self.__gpsDict['locStat'] = locRes
                    # ---------- 维度 ---------- #
                    dimfloat = resList[3]
                    # print(dimfloat)
                    if dimfloat != '':
                        dimDu = dimfloat[0:2]
                        dimFen = dimfloat[2:]
                        dimRes = int(dimDu) + float(dimFen) / 60
                        # print(dimRes)
                    else:
                        dimRes = None
                    self.__gpsDict['dim'] = dimRes
                    # ---------- 南北纬 ---------- #
                    nsDimStat = resList[4]
                    if nsDimStat != '':
                        nsDimRes = nsDimStat
                    else:
                        nsDimRes = None
                    self.__gpsDict['nsDim'] = nsDimRes
                    # ---------- 经度 ---------- #
                    litFloat = resList[5]
                    if litFloat != '':
                        litDu = litFloat[0:3]
                        litFen = litFloat[3:]
                        litRes = int(litDu) + float(litFen) / 60
                    else:
                        litRes = None
                    self.__gpsDict['lit'] = litRes
                    # ---------- 东西经 ---------- #
                    ewLitStat = resList[6]
                    if ewLitStat == '':
                        ewLitRes = None
                    else:
                        ewLitRes = ewLitStat
                    self.__gpsDict['ewLit'] = ewLitRes
                    # ---------- 地面速率 km/h ---------- #
                    gdRate = resList[7]
                    if gdRate != '':
                        gdRateRes = round(float(gdRate) * 1.85, 2)
                    else:
                        gdRateRes = None
                    self.__gpsDict['gdRate'] = gdRateRes
                    # ---------- 地面航向度 正北顺时针 ---------- #
                    gdDirect = resList[8]
                    if gdDirect != '':
                        gdDirRes = gdDirect
                    else:
                        gdDirRes = None
                    self.__gpsDict['gdDirect'] = gdDirRes
                    # ---------- 日期 ---------- #
                    dateStr = resList[9]
                    if dateStr != '':
                        dateD, dateM, dateY = re.findall(r'\w{2}', dateStr)
                        dateY = f"20{dateY}"
                        dateRes = f'{dateY}/{dateM}/{dateD}'
                    else:
                        dateRes = None
                    self.__gpsDict['date'] = dateRes

    def openGPS(self):
        """
        描述：启动GPS线程，不断的更新GPRMC数据包
        参数：无
        返回值：无
        """
        if self.__threadGPS is None:
            self.__threadGPSStat = True
            self.__threadGPS = threading.Thread(target=self.__updateGPRMC)
            self.__threadGPS.setDaemon(True)
            self.__threadGPS.start()
            self.__glDebug.info("GPS线程打开成功!")
        else:
            self.__glDebug.info("GPS线程并已经打开了!", "Warn")

    def closeGPS(self):
        """
        描述：关闭GPS线程，停止更新GPRMC数据包，并清空
        参数：无
        返回值：无
        """
        if self.__threadGPS is not None:
            self.__threadGPSStat = False
            self.__threadGPS.join()
            self.__threadGPS = None
            self.__glDebug.info("GPS线程关闭成功!")
        else:
            self.__glDebug.info("GPS线程并未打开!", "Warn")

    def getGPSTime(self) -> Optional[str]:
        """
        描述：得到GPS的当前时间
        参数：无
        返回值：返回时间字符串[str]->'HH:MM:SS'
        """
        return self.__gpsDict['time']

    def getGPSDim(self) -> tuple:
        """
        描述：得到GPS获得的维度信息
        参数：无
        返回值：返回维度信息[tuple]->('N'|'S'，[float])
        """
        return self.__gpsDict['nsDim'], self.__gpsDict['dim']

    def getGPSLit(self) -> tuple:
        """
        描述：得到GPS获得的经度信息
        参数：无
        返回值：返回经度信息[tuple]->('W'/'E',[float])
        """
        return self.__gpsDict['ewLit'], self.__gpsDict['lit']

    def getGPSRate(self) -> Optional[float]:
        """
        描述：得到GPS获得的地面速率信息
        参数：无
        返回值：返回地面速率KM/h[float]
        """
        return self.__gpsDict['gdRate']

    def getGPSDirect(self) -> Optional[float]:
        """
        描述：得到GPS获得的正北航向偏角
        参数：无
        返回值：返回正北航向偏角0~360[float]->xxx
        """
        return self.__gpsDict['gdDirect']

    def getGPSDate(self) -> Optional[str]:
        """
        描述：得到GPS获得的日期字符串
        参数：无
        返回值：返回日期字符串[str]->"xxxx/xx/xx"
        """
        return self.__gpsDict['date']

    def getDebugMsg(self) -> Optional[str]:
        """
        描述：得到调试通道的信息
        参数：无
        返回值：信息[str]->"xxx"
        """
        if not self.__glDebugQueue.empty():
            return self.__glDebugQueue.get()
        else:
            return None


class Battery:

    def __init__(self, logging=True):
        if logging:
            self.__glDebugQueue = Queue(5)
        else:
            self.__glDebugQueue = None
        self.__glDebug = Debug(self.__glDebugQueue, True, "下位机系统-电池模块")
        self.__taskStatus = False

        self.__ser = serial.Serial("/dev/ttyAMA0", 9600, timeout=3)
        self.__RESULT = {"version": None,
                         "recharge": None,
                         "power": None,
                         "vount": None
                         }
        self.__task = None

    def openBatRead(self):
        """
        描述：打开电池信息读取线程，不断更新电池的信息
        参数：无
        返回值：无
        """
        if self.__task is None:
            self.__taskStatus = True
            self.__task = threading.Thread(target=self.__getResult, daemon=True)
            self.__task.start()
            self.__glDebug.info("电池信息读取线程开启成功!")
        else:
            self.__glDebug.warn("电池信息读取线程已经开启，请勿重复开启！")

    def __getResult(self):
        while True:
            if not self.__taskStatus:
                self.__glDebug.info("主板模块请求结束线程，即将关闭该线程!", "Warn")
                break
            try:
                result = self.__ser.readline().decode().replace('\n', '')
                if re.search(r'^\$ SmartUPS V.+,Vin .+,BATCAP \d+,Vout \d+ \$$', result) is None:
                    continue
                else:
                    result = result.replace('$', '').replace(' ', '')
                    resultList = result.split(',')
                    version = resultList[0].replace('SmartUPS', '')
                    recharge = resultList[1].replace('Vin', '')
                    power = resultList[2].replace('BATCAP', '')
                    vount = resultList[3].replace('Vout', '')
                    self.__RESULT["version"] = version
                    self.__RESULT["recharge"] = True if re.search(r'GOOD', recharge) is not None else False
                    self.__RESULT["power"] = re.search(r'\d+', power).group(0)
                    self.__RESULT["vount"] = re.search(r'\d+', vount).group(0)
            # except serial.SerialException:
            # self.__taskDebug.pushInfo(f"遇到未知错误--{repr(e)}--，重新启动电池串口！", "Warn")
            # self.__ser.close()
            # self.__ser.open()
            except BaseException:
                # self.__taskDebug.pushInfo(f"遇到未知错误--{repr(e)}--，重新启动电池串口！", "Warn")
                self.__ser.close()
                self.__ser.open()

    def getBatVersion(self) -> Optional[str]:
        """
        描述：得到电池的版本信息
        参数：无
        返回值：电池的版本信息[str]->"xxx"
        """
        return self.__RESULT["version"]

    def getBatCharge(self) -> Optional[bool]:
        """
        描述：得到电池的充能状态
        参数：无
        返回值：电池的充能状态[bool]
        """
        return self.__RESULT["recharge"]

    def getBatPower(self) -> Optional[int]:
        """
        描述：得到电池的当前电量
        参数：无
        返回值：电池的当前电量[int]->xx(%)
        """
        return self.__RESULT["power"]

    def getBatVount(self) -> Optional[int]:
        """
        描述：得到电池的当前电压
        参数：无
        返回值：电池的当前电压[int]->xxxx(mv)
        """
        return self.__RESULT["vount"]

    def closeBatRead(self):
        """
        描述：关闭电池信息读取线程，停止更新电池信息并且清空
        参数：无
        返回值：无
        """
        if self.__task is None:
            self.__glDebug.warn("电池信息读取线程并未开启,关闭失败！")
        else:
            self.__taskStatus = False
            self.__task.join()
            self.__task = None
            self.__glDebug.info("电池信息读取线程关闭成功!")


if __name__ == '__main__':
    lastTime = time.time()
    mbModule = MainBoard()
    netModule = NetWork()
    mapModule = Map()
    batModule = Battery()

    print("——————————————即将打开各个模块内部线程，并且打开网络——————————————————")
    mbModule.openMBScan(1)
    netModule.openGPS()
    batModule.openBatRead()

    print("\n-----------请等待，1s后开始测试各模块信息读取功能----------")
    time.sleep(1)
    nums = 1
    while nums <= 40:
        try:
            print(">>>>>以下是主板模块测试>>>>>")
            cpuUsage = mbModule.getCpuUsage()
            cpuTemp = mbModule.getCpuTemp()
            memUsage = mbModule.getMemPer()
            gnbDown, gnbUp = mbModule.getNetDevSpeed("ppp0")
            print(f"CPU使用率：{cpuUsage}% | CPU温度：{cpuTemp}°C")
            print(f"内存当前使用率：{memUsage}%")
            print(f"gnb通道下载流量：{gnbDown}KB/s | gnb通道上传流量：{gnbUp}KB/s")
            print(">>>>>以下是网络模块测试>>>>>")
            netSignal = netModule.getNetStatus()
            netStatus = netModule.getNetOpened()
            netGPSLit, netGPSDim = netModule.getGPSLit(), netModule.getGPSDim()
            netGPSTime, netGPSDate = netModule.getGPSTime(), netModule.getGPSDate()
            netGPSRate, netGPSDirect = netModule.getGPSRate(), netModule.getGPSDirect()
            print(f"网络信号(5格为满格)：{netSignal}")
            print(f"网络状态：{'开启' if netStatus else '关闭'}")
            print(f"GPS的经纬度为：{netGPSLit}，{netGPSDim}")
            print(f"GPS当前日期：{netGPSDate} | GPS当前时间：{netGPSTime}")
            print(f"GPS移动速率：{netGPSRate}km/h")
            print(f"GPS当前方向：距离正北顺时针{netGPSDirect}°")
            print(">>>>>以下是电池模块测试>>>>>")
            batVersion = batModule.getBatVersion()
            batVount = batModule.getBatVount()
            batCharge = batModule.getBatCharge()
            batPower = batModule.getBatPower()
            print(f"当前电池版本为：{batVersion}")
            print(f"当前电池的电压：{batVount}mV")
            print(f"当前电池的充电状态为：{'正在充电' if batCharge else '未充电'}")
            print(f"当前电池的电量：{batPower}%")
            print(f"==========这是第{nums}次读取数据==========")
            time.sleep(5)
            nums += 1
        except KeyboardInterrupt:
            break
    print("\n-----------测试完毕，1s后开始将关闭各项线程并结束程序----------")
    mbModule.closeMBScan()
    netModule.closeGPS()
    # batModule.closeBatRead()

    """
    netModule.openNet()
    netModule.waitNetOpen()
    netModule.openGPS()
    while True:
        try:
            x, y = netModule.getGPSLit()[1], netModule.getGPSDim()[1]
            res = mapModule.gpsToBD((x, y))
            print(res)
            time.sleep(1) 
        except KeyboardInterrupt:
            break
    netModule.closeGPS()
    
    print(netModule.getGPSDim())

    print(time.time()-lastTime)
    """
